package sk.vrto.web.presenters;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.eventbus.Subscribe;
import sk.vrto.domain.Contact;
import sk.vrto.domain.ContactCreation;
import sk.vrto.domain.Email;
import sk.vrto.domain.User;
import sk.vrto.service.dao.ContactRepository;
import sk.vrto.service.email.EmailService;
import sk.vrto.web.base.Presenter;
import sk.vrto.web.events.ContactInsertedEvent;
import sk.vrto.web.events.ContactRemovedEvent;
import sk.vrto.web.events.NewEmailEvent;
import sk.vrto.web.events.UiEmailEvent;
import sk.vrto.web.views.NewEmailView;

import java.util.Collection;

public class NewEmailPresenter extends Presenter<NewEmailView> {

    /**
     * FW/RE decorator
     */
    public static final String FW_RE_DECORATOR =
            "<br />------------------------------- <b>Original Message</b>-------------------------------<br />";

    private final ContactRepository contactRepository;
    private final EmailService emailService;
    private final User user;

    /**
     * @param contactRepository Repository for accessing contacts
     * @param emailService Service for sending emails
     * @param user Logged user
     */
    public NewEmailPresenter(ContactRepository contactRepository,
            EmailService emailService, User user) {
        this.contactRepository = contactRepository;
        this.emailService = emailService;
        this.user = user;
    }

    /**
     * View will be aware of new contact in dropdown autocompletion.
     * @param e Triggering event
     */
    @Subscribe
    public void onContactInsert(ContactInsertedEvent e) {
        view.insertContact(e.getNewContact().getEmail());
    }

    /**
     * View will remove deleted contact from dropdown autocompletion.
     * @param e Triggering event
     */
    @Subscribe
    public void onContactDelete(ContactRemovedEvent e) {
        view.deleteContact(e.getRemovedContact());
    }

    /**
     * Prepares window for forwarding email
     * @param e Triggering event
     */
    @Subscribe
    public void onForwardEmail(UiEmailEvent.FwEvent e) {
        prepareEmailWindow(e.getEmail(), "FORWARD: ");
    }

    /**
     * Prepares window for replying to email
     * @param e Triggering event
     */
    @Subscribe
    public void onReplyEmail(UiEmailEvent.ReEvent e) {
        view.getContactsBox().setValue(e.getEmail().getContact().getEmail());
        prepareEmailWindow(e.getEmail(), "REPLY: ");
    }

    /**
     * Pre-sets value for contact in NewEmailEvent
     * @param e Triggering event
     */
    @Subscribe
    public void onNewEmail(NewEmailEvent e) {
        view.getContactsBox().setValue(e.getContact().getEmail());
    }

    /**
     * Prepares view and propagates {@link UiEmailEvent.OpenWindowEvent}
     * @param email Email to use in FW/RE content
     * @param fwreString FW or RE decoration
     */
    private void prepareEmailWindow(Email email, String fwreString) {
        view.getTitle().setValue(fwreString + email.getTitle());
        view.getMailArea().setValue(FW_RE_DECORATOR + email.getContent());
        eventBus.post(new UiEmailEvent.OpenWindowEvent());
    }

    /**
     * Constructs email from UI values and sends it using {@code emailService}.
     * <br />Sender address is obtained from the account of the logged user.
     * <br />Receiver address is obtained from the corresponding contact.
     * <br />If no such contact exists, new one is created.
     * @param recipient Recepient of the email
     * @param title Title of the email
     * @param content Textual content of the email
     */
    public void sendMail(String recipient, String title, String content) {
        ContactCreation creation = contactRepository.getOrCreate(recipient, user);
        if (creation.isFreshlyCreated()) {
            eventBus.post(new ContactInsertedEvent(creation.getContact()));
        }
        Email email = new Email(creation.getContact(), title, content);
        emailService.send(user.getEmailAccount(), email);
    }

    /**
     * Filters addresses from the contact list
     * @return Collection of addresses
     */
    public Collection<String> getAddresses() {
        Collection<Contact> contacts = contactRepository.loadContatsForUser(user);
        return Collections2.transform(contacts, new Function<Contact, String>() {
            @Override
            public String apply(Contact input) {
                return input.getEmail();
            }
        });
    }
}
